const path = require("path");//nodejs核心模块，专门用来处理路径问题
const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require("terser-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
const { VueLoaderPlugin } = require('vue-loader');
const { DefinePlugin } = require("webpack")
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
// const PreloadWebpackPlugin = require("@vue/preload-webpack-plugin");


// nodejs核心模块，直接使用
const os = require("os")
// cpu核数
const threads = os.cpus().length;

function getStyleLoaders(pre) {
  return [
    MiniCssExtractPlugin.loader,
    'css-loader', //将css资源编译成commonjs的模块到js中
    {
      loader: 'postcss-loader',
      options: {
        postcssOptions: {
          plugins: [
            [
              'postcss-preset-env',
            ],
          ],
        },
      },
    },
    pre
  ].filter(Boolean) //array.filter(Boolean)：过滤假数据（false,0,-0."",null,undefined,NaN）
}


module.exports = {
  // 入口
  entry: "./src/main.js",
  // 输出
  output: {
    // 文件的输出路径
    path: path.resolve(__dirname, "../dist"),
    // 文件名
    filename: "static/js/[name].[contenthash:10].js",
    // 动态导入输出资源命名方式
    chunkFilename: "static/js/[name].chunk.[contenthash:10].js",//chunk区分于主文件
    // 图片、字体等资源命名方式
    assetModuleFilename: 'static/media/[contenthash:10][ext]',
    // 自动清空上次打包的内容
    clean: true,
  },
  // 加载器
  module: {
    rules: [ 
      // loader的配置
      {
        test: /\.css$/, //只检测.css文件
        use: getStyleLoaders(),
      },
      {
        test: /\.less$/, //只检测.less文件
        use: getStyleLoaders("less-loader"),
      },
      {
        test: /\.s[ac]ss$/, //只检测.less文件
        use: getStyleLoaders("sass-loader"),
      },
      // 将小于6kb的图片转为data URL(base64编码)，大于的不转，减少连接
      // 默认8kb，通过parser.dataUrlCondition.maxSize自定义
      {
        test: /\.(png|jpe?g|gif|webp|svg)$/,
        type: 'asset',
        parser: {
          // 将小于4kb的文件转化为base64的url
          dataUrlCondition: {
            maxSize: 6 * 1024 // 6kb
          }
        },
      },
      {
        test: /\.(ttf|woff2?|mp3|mp4|avi)$/,
        type: 'asset/resource',
      },
      {
        test: /\.js$/,
        include: path.resolve(__dirname, 'src'),
        use: [
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: true, // 开启babel编译缓存
              cacheCompression: false, // 缓存文件不要压缩
            }
          }
        ]
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
    ],
  },
  // 插件
  plugins: [
    new ESLintPlugin({
      context: path.resolve(__dirname, '../src'),
      exclude: "node_modules", // 默认值
      cache: true,//开启缓存
      // 缓存目录
      cacheLocation: path.resolve(
        __dirname,
        "../node_modules/.cache/.eslintcache"
      ),
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    // 将public内资源赋值到dist中
    new CopyPlugin({
      patterns: [
        {
          from: path.resolve(__dirname, '../public'),
          to: path.resolve(__dirname, '../dist'),
          globOptions: {
            // 忽略index.html文件
            ignore: ["**/index.html"]
          }
        },
      ],
    }),
    new VueLoaderPlugin(),
    // cross-env定义的环境变量给打包工具使用
    // DefinePlugin定义的环境变量是给源代码使用的
    new DefinePlugin({
      __VUE_OPTIONS_API__: true,
      __VUE_PROD_DEVTOOLS__: false,
      __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false,
    }),
    // 提取css成单独文件
    new MiniCssExtractPlugin({
      // 定义输出文件名和目录
      filename: "static/css/[name].[contenthash:10].css",
      chunkFilename: "static/css/[name].chunk.[contenthash:10].css"
    }),

    new ImageMinimizerPlugin({
      minimizer: {
        implementation: ImageMinimizerPlugin.imageminGenerate,
        options: {
          plugins: [
            ["gifsicle", { interlaced: true }],
            ["jpegtran", { progressive: true }],
            ["optipng", { optimizationLevel: 5 }],
            [
              "svgo",
              {
                plugins: [
                  "preset-default",
                  "prefixIds",
                  {
                    name: "sortAttrs",
                    params: {
                      xmlnsOrder: "alphabetical",
                    },
                  },
                ],
              },
            ],
          ],
        },
      },
    }),

  ],
  // 压缩的放这里
  optimization: {
    // 代码分割配置
    splitChunks: {
      chunks: "all", // 对所有模块都进行分割
    },
    // 将依赖关系单独一个文件，便于只更新改动的文件名
    runtimeChunk: {
      name: entrypoint => `runtime~${entrypoint.name}.js`,
    },
    minimizer: [
      new CssMinimizerPlugin(), //压缩css
      // 当生产模式会默认开启TerserPlugin，但是我们需要进行其他配置，就要重新写了
      new TerserPlugin({ //压缩js
        parallel: threads, // 开启多进程
      }),
    ],
  },
  resolve: {
    // 自动补全文件扩展名
    extensions: ['.vue', '.js', '.json'],
  },
  // 模式
  mode: "production",
  devtool: "source-map"
}
